package titan.wizards;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.ui.INewWizard;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.dialogs.ContainerSelectionDialog;
import titan.messages.Messages;

/**
 * Wizards for creating elements of Titan Framework inherit from this class.
 * The class performs the validation of the selected project,
 * accepting only startup when given a valid Titan project
 */
public abstract class BaseTitanWizard extends Wizard implements INewWizard {
	protected boolean canInit;
	protected IProject project;

	public BaseTitanWizard() {
		canInit = false;
	}

	/**
	 * Tries to get a Titan project using the passed object selection.
	 * Calls the {@link BaseTitanWizard#validateProject(IProject, boolean) validateProject} method
	 * to validate the selected project.
	 * If a project is not selected an error message is displayed.
	 * This method is called after the constructor and before other methods are called.
	 * @param workbench
	 * @param selection
	 */
	public final void init(IWorkbench workbench, IStructuredSelection selection) {
		// if selection is not empty, get first element
		if(selection != null && !selection.isEmpty()) {
			Object element = selection.getFirstElement();
			// if element is a resource, get the associated project
		    if (element instanceof IResource) {
		    	IProject project = ((IResource)element).getProject();
		    	// validate the project and inform error if it's not valid
				try {
					validateProject(project, false);
				} catch (Exception e) {
					MessageDialog.openError(getShell(), Messages.Error, e.getMessage());
				}
			// inform error because element isn't a resource, so it isn't valid
		    } else
				MessageDialog.openError(getShell(), Messages.Error, Messages.InvalidTitanProject);
		}
	}

	/**
	 * Initializes this creation wizard using the passed Titan project.
	 * This method is called by the {@link BaseTitanWizard#getStartingPage() getStartingPage} method
	 * when a valid Titan project is selected
	 * @throws Exception if there was an error while initializing project
	 */
	protected abstract void init() throws Exception;

	/**
	 * Open project selection dialog
	 * @return the selected project name
	 * @throws Exception if {@link BaseTitanWizard#validateProject(IProject, boolean) validateProject} threw it
	 */
	protected final boolean selectProject() throws Exception {
		// creates a container selection dialogs
		ContainerSelectionDialog dialog = new ContainerSelectionDialog(
				getShell(), ResourcesPlugin.getWorkspace().getRoot(), false,
				Messages.SelectProject_desc);
		dialog.setTitle(Messages.SelectProject);
		// open dialog and verifies if the OK button was pressed
		if (dialog.open() == ContainerSelectionDialog.OK) {
			// get the selected element in the dialog
			Object[] result = dialog.getResult();
			// get the project associated to the selected element
			IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
			IResource resource = root.findMember(((Path) result[0]).toString());
			IProject project = resource.getProject();
			// validate project
			return validateProject(project, true);
		}
		return false;
	}

	/**
	 * Tests if it's a valid Titan Project
	 * @param project the project to test
	 * @param askAgain true to ask for another project, if the passed one is invalid, false otherwise
	 * @return true if it's a valid project, false otherwise
	 * @throws Exception if it can't get project nature
	 */
	protected final boolean validateProject(IProject project, boolean askAgain) throws Exception {
		// if the passed project doesn't have a Titan nature, inform error
		if(project.getNature("titan.natures.ProjectNature") == null){ //$NON-NLS-1$
			MessageDialog.openError(getShell(), Messages.Error, Messages.InvalidTitanProject);
			// if askAgain is true, ask for another project, otherwise return false
			if(askAgain)
				return selectProject();
			return false;
		}
		// if the passed project is a Titan project, save it and return true
		else{
			this.project = project;
			canInit = true;
			return true;
		}
	}

	/**
	 * {@inheritDoc}
	 */
	public final IWizardPage getStartingPage() {
		try {
			// if it can't init, select project, if no project was selected, return null
			if(!canInit)
				if(!selectProject())
					return null;
			// if it can init, calls the init action
			init();
		} catch (Exception e) {
			MessageDialog.openError(getShell(), Messages.Error, e.getMessage());
			return null;
		}
		// it's initiated, now returns the first page
		return getFirstPage();
	}

	/**
	 * Returns the first page to be shown in this wizard
	 * @return the first wizard page
	 */
	protected abstract IWizardPage getFirstPage();
}